package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.NestedQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.respoistory.GoodsRepository;
import com.atguigu.tingshu.search.respoistory.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class SearchServiceImpl implements SearchService {


    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String dimension) {
        //  hget key field;
        //  return  (List<AlbumInfoIndex>)this.redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX + category1Id, dimension);
        return (List<AlbumInfoIndex>) this.redisTemplate.boundHashOps(RedisConstant.RANKING_KEY_PREFIX+category1Id).get(dimension);
    }

    @Override
    public void updateLatelyAlbumRanking() {
        //  先获取到所有的一级分类数据集合.
        Result<List<BaseCategory1>> baseCategory1ListResult = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCategory1ListResult,"返回一级分类集合数据集为空");
        //  获取集合数据
        List<BaseCategory1> baseCategory1List = baseCategory1ListResult.getData();
        Assert.notNull(baseCategory1List,"一级分类数据为空");
        //  操作es ，还需要操作redis。 传递过来?
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            //  循环排序规则：
            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            for (String ranking : rankingDimensionArray) {
                //  执行dsl 语句 并获取到数据集
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(f -> f.index("albuminfo").query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
                                    .sort(s -> s.field(b -> b.field(ranking).order(SortOrder.Desc)))
                                    .size(10)
                            ,
                            AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //  将获取的数据存储到缓存：redis 1.数据类型 2.考虑key起名 3.存储数据
                //  set key value; hset key field value; lpush key value sadd key member zadd->排序 key score member
                //  hset key = category1Id field=hotScore value=List<>
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                //  定义key
                String key = RedisConstant.RANKING_KEY_PREFIX+baseCategory1.getId();
                //  存储数据
                this.redisTemplate.opsForHash().put(key,ranking,albumInfoIndexList);
                //  this.redisTemplate.boundHashOps(key).put(ranking,albumInfoIndexList);
            }
        }

    }

    @Override
    public List<String> completeSuggest(String keyword) {
        //  先生成dsl语句，获取数据.
//        SearchResponse<SuggestIndex> searchResponse = null;

        //  创建一个SearchRequest 对象
//        SearchRequest.Builder request = new SearchRequest.Builder();
//        request.index("suggestinfo").suggest(f -> f.suggesters("suggestionKeyword", s -> s.prefix(keyword).completion(
//                                c -> c.field("keyword").fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)
//                        ))
//                        .suggesters("suggestionkeywordPinyin", s -> s.prefix(keyword).completion(
//                                c -> c.field("keywordPinyin").fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)
//                        ))
//                        .suggesters("suggestionkeywordSequence", s -> s.prefix(keyword).completion(
//                                c -> c.field("keywordSequence").fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)
//                        ))
//        );

        SearchResponse<SuggestIndex> searchResponse = null;
        //  打印dsl 语句
//        SearchRequest searchRequest = request.build();
//        System.out.println("dsl:\t"+searchRequest.toString());
//        try {
//            searchResponse = elasticsearchClient.search(searchRequest, SuggestIndex.class);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
        try {
            searchResponse = elasticsearchClient.search(f -> f.index("suggestinfo")
                            .suggest(s -> s.suggesters("suggestionKeyword", u -> u.prefix(keyword)
                                    .completion(c -> c.field("keyword").size(10).skipDuplicates(true)
                                            .fuzzy(z -> z.fuzziness("auto"))))
                                    .suggesters("suggestionkeywordPinyin", s1 -> s1.prefix(keyword).completion(
                                            c -> c.field("keywordPinyin").fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)
                                    ))
                                    .suggesters("suggestionkeywordSequence", s2 -> s2.prefix(keyword).completion(
                                            c -> c.field("keywordSequence").fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)
                                    ))
                            )
                    ,
                    SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取数据之后，将数据统一接收。
        HashSet<String> set = new HashSet<>();
        set.addAll(this.parseResultData(searchResponse, "suggestionKeyword"));
        set.addAll(this.parseResultData(searchResponse, "suggestionkeywordPinyin"));
        set.addAll(this.parseResultData(searchResponse, "suggestionkeywordSequence"));
        //  v2.0 版本：如果集合数据不够10条，则执行一个查询操作.
        /*
        GET /suggestinfo/_search
        {
          "query": {
            "match": {
              "title": "三国"
            }
          }
        }
         */
        if (set.size()<10){
            //  执行dsl语句，获取结果，将set集合补充到10条数据
            SearchResponse<SuggestIndex> response = null;
            try {
                response = elasticsearchClient.search(f -> f.index("suggestinfo").query(q -> q.match(m -> m.field("title").query(keyword))), SuggestIndex.class);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //  获取结果集.
            List<Hit<SuggestIndex>> hits = response.hits().hits();
            if (!CollectionUtils.isEmpty(hits)){
                //  循环遍历
                for (Hit<SuggestIndex> hit : hits) {
                    //  获取专辑标题
                    String title = hit.source().getTitle();
                    //  添加数据
                    set.add(title);
                    //  判断
                    if (set.size()>=10){
                        //  return break continue;
                        break;
                    }
                }
            }
        }

        //  返回数据
        return new ArrayList<>(set);
    }

    private Collection<String> parseResultData(SearchResponse<SuggestIndex> searchResponse, String suggestionKeyword) {
        //  final List<String>[] stringList = new List[]{new ArrayList<>()};
        ArrayList<String> stringArrayList = new ArrayList<>();
        //  获取数据。
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(suggestionKeyword);
        if (!CollectionUtils.isEmpty(suggestionList)) {
            suggestionList.stream().forEach(suggestIndexSuggestion -> {
                List<CompletionSuggestOption<SuggestIndex>> list = suggestIndexSuggestion.completion().options();
                //  判断
                if (!CollectionUtils.isEmpty(list)) {
                    //  获取到专辑标题数据
                    //                 stringList[0] = list.stream().map(suggestIndexCompletionSuggestOption -> {
                    //                    String title = suggestIndexCompletionSuggestOption.source().getTitle();
                    //                    return title;
                    //                }).collect(Collectors.toList());
                    for (CompletionSuggestOption<SuggestIndex> suggestIndexCompletionSuggestOption : list) {
                        //  获取到专辑标题数据
                        stringArrayList.add(suggestIndexCompletionSuggestOption.source().getTitle());
                    }
                }
            });
        }

        //  返回数据
        return stringArrayList;
    }

    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        //  创建list集合 key=baseCategory3 key=list
        //  List<Map<String, Object>> list = new ArrayList<>();
        //  根据一级分类Id找对应的三级置顶数据;
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);
        Assert.notNull(baseCategory3ListResult, "三级分类数据结果集为空");
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "三级分类数据为空");
        //  将这个集合转换为map 集合. list-->map; key=category3Id value=BaseCategory3;
        //  Map<Long, BaseCategory3> BaseCategory3ToMap = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        // R apply(T t);
        Map<Long, BaseCategory3> baseCategory3ToMap = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));

        //  获取三级分类id 集合.
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        //  数据类型转换： List<Long> ---> List<FieldValue>
        List<FieldValue> category3IdFieldList = category3IdList.stream().map(id -> FieldValue.of(id)).collect(Collectors.toList());
        //  聚合：获取每层分类下的对应的专辑数据: top_his
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(f -> f.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id").terms(e -> e.value(category3IdFieldList))))
                            .aggregations("groupByCategory3IdAgg", a -> a.terms(r -> r.field("category3Id").size(6))
                                    .aggregations("topTenHotScoreAgg", g -> g.topHits(b -> b.size(6).sort(s -> s.field(p -> p.field("hotScore").order(SortOrder.Desc)))))
                            )
                    ,
                    AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取数据：
        Aggregate groupByCategory3IdAgg = searchResponse.aggregations().get("groupByCategory3IdAgg");
        //  list=AlbumInfoIndex
        List<Map<String, Object>> list = groupByCategory3IdAgg.lterms().buckets().array().stream().map(bucket -> {
            //  创建map 集合
            Map<String, Object> map = new HashMap<>();
            //  获取到三级分类Id
            long category3Id = bucket.key();
            //  获取专辑集合列表.
            List<AlbumInfoIndex> albumInfoIndexList = bucket.aggregations().get("topTenHotScoreAgg").topHits().hits().hits().stream().map(hit -> {
                //  获取的数据.
                String dataJson = hit.source().toString();
                //  数据类型转换
                AlbumInfoIndex albumInfoIndex = JSONObject.parseObject(dataJson, AlbumInfoIndex.class);
                //  返回数据
                return albumInfoIndex;
            }).collect(Collectors.toList());
            //  存储三级分类对象;
            map.put("baseCategory3", baseCategory3ToMap.get(category3Id));
            map.put("list", albumInfoIndexList);
            //  返回map 集合
            return map;
        }).collect(Collectors.toList());

        //  返回数据。
        return list;
    }

    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //  利用java 客户端动态生成DSL 语句；
        /*
            1.  先生成一个查询请求对象.
            2.  执行查询请求
            3.
         */
        SearchRequest searchRequest = this.queryBuildDsl(albumIndexQuery);
        //  声明对象
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  将返回数据封装到 albumSearchResponseVo 对象中。 给 private List<AlbumInfoIndexVo> list = new ArrayList<>(); 赋值
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(searchResponse);
        //  赋值：
        /*
            private List<AlbumInfoIndexVo> list = new ArrayList<>();
            private Long total;//总记录数
            private Integer pageSize;//每页显示的内容
            private Integer pageNo;//当前页面
            private Long totalPages;
         */
        albumSearchResponseVo.setTotal(searchResponse.hits().total().value());
        //  默认每页显示的条数
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        //  默认从第几页开始
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        //  计算总页数 10 3 4 | 9 3 3
//        long totalPages =  albumSearchResponseVo.getTotal()%albumIndexQuery.getPageSize()==0?albumSearchResponseVo.getTotal()/albumIndexQuery.getPageSize():albumSearchResponseVo.getTotal()/albumIndexQuery.getPageSize()+1;
        long totalPages = (albumSearchResponseVo.getTotal() + albumIndexQuery.getPageSize() - 1) / albumIndexQuery.getPageSize();
        albumSearchResponseVo.setTotalPages(totalPages);
        return albumSearchResponseVo;
    }

    /**
     * 获取返回对象
     *
     * @param searchResponse
     * @return
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        //  赋值：private List<AlbumInfoIndexVo> list = new ArrayList<>();
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        List<AlbumInfoIndexVo> albumInfoIndexVoList = searchResponse.hits().hits().stream().map(albumInfoIndexHit -> {
            //  获取到专辑对象
            AlbumInfoIndex albumInfoIndex = albumInfoIndexHit.source();
            //  创建 AlbumInfoIndexVo 对象
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            //  属性拷贝：
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            //  设置高亮：
            if (null != albumInfoIndexHit.highlight().get("albumTitle")) {
                //  有高亮设置
                String albumTitle = albumInfoIndexHit.highlight().get("albumTitle").get(0);
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            //  返回数据
            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        //  赋值：
        albumSearchResponseVo.setList(albumInfoIndexVoList);
        //  返回数据
        return albumSearchResponseVo;
    }

    /**
     * 生成查询对象
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest queryBuildDsl(AlbumIndexQuery albumIndexQuery) {
        //  创建一个SearchRequest.Builder 对象 {}
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        //  创建bool
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
        //  判断是否根据关键词查询. 关键词检索第一个入口：
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            //  构建条件.
            boolQueryBuilder.should(f -> f.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())));
            boolQueryBuilder.should(f -> f.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())));
            //  高亮： key=应该是高亮的字段
            searchRequestBuilder.highlight(f -> f.fields("albumTitle", h -> h.preTags("<span style=color:red>").postTags("</span>")));
        }
        //  分类查询：第二个入口
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        //  排序：order=1:desc 1:asc 综合排序1=hotScore 播放量2=playStatNum 发布时间3=createTime
        //  先获取排序规则
        String order = albumIndexQuery.getOrder();
        //  判断排序规则
        if (!StringUtils.isEmpty(order)) {
            //  order=1:desc 1:asc 根据前端传递数值判断传递排序的字段.
            String[] split = order.split(":");
            //  判断 数组长度 字符串长度 文件长度 集合长度 ():方法 属性
            if (null != split && split.length == 2) {
                //  声明一个变量接收排序字段
                String field = "";
                //  判断
                switch (split[0]) {
                    case "1":
                        field = "hotScore";
                        break;
                    case "2":
                        field = "playStatNum";
                        break;
                    case "3":
                        field = "createTime";
                        break;
                }
                String finalField = field;
                searchRequestBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }
        //  默认按照_score 排序
        //        else {
        //            //  不给默认排序按照_score 这个值进行排序.
        //            searchRequestBuilder.sort(s->s.field(f->f.field("_source").order(SortOrder.Desc)));
        //        }
        //        @Schema(description = "属性（属性id:属性值id）")
        //        private List<String> attributeList;
        //  先获取到属性：属性值
        List<String> attributeList = albumIndexQuery.getAttributeList();
        //  判断
        if (!CollectionUtils.isEmpty(attributeList)) {
            //  循环遍历.
            for (String attribute : attributeList) {
                //  分割：
                String[] split = attribute.split(":");
                //  判断
                if (null != split && split.length == 2) {
                    // 属性Id split[0];
                    // 属性值Id split[1];
                    //  NestedQuery.of(f->f.path().query(q->q.bool(b->b.must(m->m.term())))).
                    //  要声明一个nested 对象.path;
                    boolQueryBuilder.filter(f -> f.nested(n -> n.path("attributeValueIndexList")
                            .query(q -> q.bool(b -> b.must(m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
                                    .must(m -> m.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
                            ))));
                }
            }
        }

        //  分页：
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(albumIndexQuery.getPageSize());

        //  汇总DSL 语句：
        //  searchRequestBuilder.query(boolQueryBuilder.build()._toQuery());
        searchRequestBuilder.query(f -> f.bool(boolQueryBuilder.build()));
        //  GET /albuminfo/_search
        searchRequestBuilder.index("albuminfo");
        //  创建一个 SearchRequest 对象
        SearchRequest searchRequest = searchRequestBuilder.build();
        //  要获取到一个完整的dsl语句：
        System.out.println("dsl:\t" + searchRequest.toString());
        //  返回数据
        return searchRequest;
    }

    @Override
    public void lowerAlbum(Long albumId) {
        this.goodsRepository.deleteById(albumId);
    }

    @Override
    public void upperAlbum(Long albumId) {
        //  本质：将数据保存到es、 数据载体：AlbumInfoIndex   es
        //  1.专辑基本信息 2.专辑属性信息 3.专辑分类信息 --专辑微服务提供数据:  4.用户信息
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        //  多线程：
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            //  判断
            Assert.notNull(albumInfoResult, "专辑返回结果为空");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑为空");
            //  赋值：
            //  处理专辑信息，属性拷贝：属性必须一致.
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            return albumInfo;
        }, threadPoolExecutor);

        //  获取属性标签
        CompletableFuture<Void> attributeCompletableFuture = CompletableFuture.runAsync(() -> {
            Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumInfoFeignClient.findAlbumAttributeValue(albumId);
            //  判断
            Assert.notNull(albumAttributeValueResult, "专辑属性结果集为空");
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueResult.getData();
            Assert.notNull(albumAttributeValueList, "专辑属性为空");
            //  想不到... 循环遍历获取数据，同时返回一个新的集合。map stream 对应的泛型：就是集合的泛型.
            List<AttributeValueIndex> attributeValueList = albumAttributeValueList.stream().map(albumAttributeValue -> {
                //  创建对象 AttributeValueIndex
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                //  赋值：
                //            attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                //            attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                BeanUtils.copyProperties(albumAttributeValue, attributeValueIndex);
                //  返回
                return attributeValueIndex;
            }).collect(Collectors.toList());
            //  给属性赋值：
            albumInfoIndex.setAttributeValueIndexList(attributeValueList);

        }, threadPoolExecutor);
        //  包含一级分类，二级分类，三级分类; 查询base_category_view 数据
        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            Result<BaseCategoryView> baseCategoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());

            Assert.notNull(baseCategoryViewResult, "专辑分类结果集为空");
            BaseCategoryView baseCategoryView = baseCategoryViewResult.getData();
            Assert.notNull(baseCategoryView, "专辑分类为空");
            //  赋值分类数据
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            albumInfoIndex.setCategory3Id(baseCategoryView.getCategory3Id());
        }, threadPoolExecutor);

//        Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            Result<UserInfoVo> userInfoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            Assert.notNull(userInfoResult, "用户结果集为空");
            UserInfoVo userInfoVo = userInfoResult.getData();
            Assert.notNull(userInfoVo, "用户为空");

            //  赋值主播
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        }, threadPoolExecutor);
        //  赋值：初始化统计信息
        int playStatNum = new Random().nextInt(100000);
        int subscribeStatNum = new Random().nextInt(100000000);
        int buyStatNum = new Random().nextInt(10000000);
        int commentStatNum = new Random().nextInt(1000000000);
        albumInfoIndex.setPlayStatNum(playStatNum);
        albumInfoIndex.setSubscribeStatNum(subscribeStatNum);
        albumInfoIndex.setBuyStatNum(buyStatNum);
        albumInfoIndex.setCommentStatNum(commentStatNum);
        //  热度排名：默认是0；
        //  albumInfoIndex.setHotScore();
        //  进行多任务组合：
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                categoryCompletableFuture,
                attributeCompletableFuture,
                userCompletableFuture).join();
        //  保存albumInfoIndex到es！ 必须先有索引库. -- 使用内置类，在启动项目的时候，会根据AlbumInfoIndex.class 中定义的数据类型与索引库名称，自动创建.
        goodsRepository.save(albumInfoIndex);

        //  初始化提词库数据:
        //  保存专辑标题
        SuggestIndex suggestIndexTitle = new SuggestIndex();
        suggestIndexTitle.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexTitle.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndexTitle.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndexTitle.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndexTitle.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        this.suggestIndexRepository.save(suggestIndexTitle);

        //  保存专辑简介
        SuggestIndex suggestIndexInfo = new SuggestIndex();
        suggestIndexInfo.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndexInfo.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndexInfo.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndexInfo.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndexInfo.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        this.suggestIndexRepository.save(suggestIndexInfo);
        //  保存专辑作者:

        //  布隆过滤器中添加专辑Id 数据.
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
    }
}
